package service

import (
    "context"
    "errors"

    "github.com/go-kratos/kratos/v2/log"
    "github.com/jinzhu/copier"
    "google.golang.org/protobuf/types/known/timestamppb"
    "mall/api/product/v1"
    "mall/app/product/internal/biz"
    "mall/app/product/internal/domain"
    "mall/pkg/util"
)

type ProductService struct {
    v1.UnimplementedProductServer
    uc  *biz.ProductUseCase
    log *log.Helper
}

func NewProductService(uc *biz.ProductUseCase, logger log.Logger) *ProductService {
    return &ProductService{
        uc:  uc,
        log: log.NewHelper(log.With(logger, "module", "service/product")),
    }
}

func (s *ProductService) Create(ctx context.Context, req *v1.ProductCreateRequest) (*v1.ProductCreateReply, error) {
    q := &domain.Product{}
    if err := copier.Copy(q, req); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    product, err := s.uc.Create(ctx, q)
    if err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }

    replyData := &v1.ProductDetailReply{}
    if err := copier.Copy(replyData, product); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    replyData.CreatedAt = timestamppb.New(product.CreatedAt)

    return &v1.ProductCreateReply{Product: replyData}, nil
}

func (s *ProductService) List(ctx context.Context, req *v1.ProductListRequest) (*v1.ProductListReply, error) {
    q := &domain.ListReq{}
    if err := copier.Copy(q, req); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }

    result, err := s.uc.List(ctx, q)
    if err != nil {
        return nil, err
    }
    reply := &v1.ProductListReply{}

    for _, product := range result.Data {
        datum := &v1.ProductDetailReply{}
        if err := copier.Copy(datum, product); err != nil {
            return nil, errors.New(util.ErrMsg(err))
        }
        datum.CreatedAt = timestamppb.New(product.CreatedAt)
        reply.Data = append(reply.Data, datum)
    }

    paginate := &v1.ProductListReply_Paginate{}
    if err := copier.Copy(paginate, result.Paginate); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    reply.Paginate = paginate
    return reply, nil
}

func (s *ProductService) Edit(ctx context.Context, req *v1.ProductEditRequest) (*v1.ProductEditReply, error) {
    q := &domain.Product{}
    if err := copier.Copy(q, req); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    product, err := s.uc.Edit(ctx, q.Id, q)
    if err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }

    replyData := &v1.ProductDetailReply{}
    if err := copier.Copy(replyData, product); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    replyData.CreatedAt = timestamppb.New(product.CreatedAt)
    return &v1.ProductEditReply{Product: replyData}, nil
}

func (s *ProductService) Detail(ctx context.Context, req *v1.ProductDetailRequest) (*v1.ProductDetailReply, error) {
    detail, err := s.uc.Detail(ctx, uint(req.Id))
    if err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }

    reply := &v1.ProductDetailReply{}
    if err := copier.Copy(reply, detail); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    reply.CreatedAt = timestamppb.New(detail.CreatedAt)
    return reply, nil
}

func (s *ProductService) AddStock(ctx context.Context, req *v1.ProductAddStockRequest) (*v1.ProductAddStockReply, error) {
    product, err := s.uc.AddStock(ctx, uint(req.Id), int(req.Num))
    if err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    replyData := &v1.ProductDetailReply{}
    if err := copier.Copy(replyData, product); err != nil {
        return nil, errors.New(util.ErrMsg(err))
    }
    replyData.CreatedAt = timestamppb.New(product.CreatedAt)
    return &v1.ProductAddStockReply{Product: replyData}, nil
}
